#include <stdlib.h>
#include <string.h>
#include "includes/myhashtable.h"

static myhentry *myhashtable_create_entry(uint8_t *key, void *value);

int myhashtable_default_hash_fun(uint8_t *key) {
    int h = 0;
    int len = strlen(key);
    // printf("[myhashtable_default_hash_fun] len: %d\n", len);
    for (int i = 0; i < len; i++)
    {
        h = 31 * h + key[i];
        // printf("[myhashtable_default_hash_fun] len: %d, after loop %d\n", len, i);
    }
    // printf("[myhashtable_default_hash_fun] len: %d, after loop, h: %d\n", len, h);
    return h;
}

int myhashtable_entry_cmp(myhentry *a, myhentry *b) {
    return strcmp(a->key, b->key);
}

myhashtable *myhashtable_create(int tlen, hash_fun hf) {
    if(hf == NULL) hf = myhashtable_default_hash_fun;
    myhashtable *ht = malloc(sizeof(myhashtable));
    mylist **t = malloc(sizeof(mylist *) * tlen);
    for (int i = 0; i < tlen; i++)
    {
        t[i] = mylist_create(100, myhashtable_entry_cmp);
    }
    ht->table = t;
    ht->table_len = tlen;
    ht->entry_size = 0;
    ht->hfun = hf;
    return ht;
}

int myhashtable_put(myhashtable *ht, uint8_t *key, void *value) {
    int hash_code = ht->hfun(key) % ht->table_len;
    // printf("after hash code\n");
    myhentry *e = myhashtable_create_entry(key, value);
    // printf("after myhashtable_create_entry\n");
    int res = mylist_append(ht->table[hash_code], e);
    // printf("after mylist_append\n");
    if(res) ht->entry_size++;
    return res;
}

void *myhashtable_get(myhashtable *ht, uint8_t *key) {
    int hash_code = ht->hfun(key) % ht->table_len;
    myhentry *e = myhashtable_create_entry(key, NULL);
    mylnode *n = mylist_find(ht->table[hash_code], e);
    if(n) return ((myhentry *)n->data)->value;
    return NULL;
}

void *myhashtable_delete(myhashtable *ht, uint8_t *key) {
    int hash_code = ht->hfun(key) % ht->table_len;
    myhentry *e = myhashtable_create_entry(key, NULL);
    mylnode *n = mylist_find(ht->table[hash_code], e);
    if(n) {
        mylist_delete(ht->table[hash_code], n);
        ht->entry_size--;
        return ((myhentry *)n->data)->value;
    }
    return NULL;
}

static myhentry *myhashtable_create_entry(uint8_t *key, void *value) {
    myhentry *e = malloc(sizeof(myhentry));
    e->key = key;
    e->value = value;
    return e;
}
